CSSE 290 Web Programming

Lecture 17: More Prototype, Scriptaculous (quick look)

Reading: 10.1; 10.2

Attribution:Except where otherwise noted, the contents of this document are Copyright 2012 Marty Stepp, Jessica Miller, and Victoria Kirst. All rights reserved. Any redistribution, reproduction, transmission, or storage of part or all of the contents in any form is prohibited without the author's expressed written permission.

Otherwise noted: Claude Anderson was given permission to modify the slides for CSSE 290 at Rose-Hulman by author Jessica Miller. The authors' original slides, based on Web Programming Step by Step, can be seen at http://webstepbook.com.
Some of the examples in some days' slides are from David Fisher at Rose-Hulman, who was kind enough to allow me to use them. My intention is to mark these examples with [DSF].

Valid HTML Valid CSS!

Today's Class Meeting Overview

Prototype (continued) amd Scriptaculous

You should skim through Chapter 10 to see what kinds of things are available, so that you'll know they are there if you need them.

You can read the details later.

Recap: DOM versus innerHTML hacking

Why not just code the previous example this way?

function slideClick() {
	$("thisslide").innerHTML += "<p>A paragraph!</p>";
}
  • Imagine that the new node is more complex:
    • ugly: bad style on many levels (e.g. JS code embedded within HTML)
    • error-prone: must carefully distinguish " and '
    • can only add at beginning or end, not in middle of child list
function slideClick() {
	$("main").innerHTML += "<p style='color: red; " +
			"margin-left: 50px;' " +
			"onclick='myOnClick();'>" +
			"A paragraph!</p>";
}

Benefits of DOM over innerHTML

function slideClick() {
	var p = document.createElement("p");
	p.className = "special";
	p.onclick = myOnClick;
	p.innerHTML = "A paragraph!";
	$("thisslide").appendChild(p);
}
.special {
	color: red;
	margin-left: 50px;
}

Problems with reading/changing styles

<button id="clickme">Click Me</button>
window.onload = function() {
	$("clickme").onclick = biggerFont;
};
function biggerFont() {
	var size = parseInt($("clickme").style.fontSize);
	size += 4;
	$("clickMe").style.fontSize = size + "pt";
}

Accessing styles in Prototype

function biggerFont() {
	// make the text bigger
	var size = parseInt($("clickme").getStyle("font-size"));
	$("clickme").style.fontSize = (size + 4) + "pt";
}

Common bug: incorrect usage of existing styles

$("main").style.top = $("main").getStyle("top") + 100 + "px";            // bad!

JavaScript: Getting/setting CSS classes

function highlightField() {
	// turn text yellow and make it bigger
	if (!$("text").className) {
		$("text").className = "highlight";
	} else if ($("text").className.indexOf("invalid") < 0) {
		$("text").className += " highlight";
	}
}

Getting/setting CSS classes in Prototype

function highlightField() {
	// turn text yellow and make it bigger
	if (!$("text").hasClassName("invalid")) {
		$("text").addClassName("highlight");
	}
}

Scriptaculous overview

Scriptaculous : a JavaScript library, built on top of Prototype, that adds:

Downloading and using Scriptaculous

<script src="http://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"
 type="text/javascript"></script>

<script src="http://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/scriptaculous.js"
 type="text/javascript"></script>

Learning about Scriptaculous

Online API documentation is incomplete (argh), but the following are useful resources:

Visual effects

(appearing)


(disappearing)


(Getting attention)

scriptaculous logo Click effects above

Adding effects to an element

element.effectName();   // for most effects

// some effects must be run the following way:
new Effect.name(element or id);
$("sidebar").shake();

var buttons = $$("results > button");
for (var i = 0; i < buttons.length; i++) {
	buttons[i].fade();
}

Effect options

element.effectName(
	{
		option: value,
		option: value,
		...
	}
);
$("my_element").pulsate({
	duration: 2.0, 
	pulses: 2
});

Effect events

$("my_element").fade({
	duration: 3.0, 
	afterFinish: displayMessage
});

function displayMessage(effect) {
	alert(effect.element + " is done fading now!");
}

Learn more about Scriptaculous

Drag and drop

Scriptaculous provides several objects for supporting drag-and-drop functionality:

Draggable

new Draggable(element or id,
	{ options }
);

Draggable example

<div id="draggabledemo1">Draggable demo. Default options.</div>
<div id="draggabledemo2">Draggable demo.
	{snap: [40,40], revert: true}</div>
document.observe("dom:loaded", function() {
	new Draggable("draggabledemo1");
	new Draggable("draggabledemo2", {revert: true, snap: [40, 40]});
});
logo Draggable demo.
Default options.
Draggable demo.
{snap:[60, 60], revert:true}

Draggables

Droppables

Droppables.add(element or id,
	{ options }
);

Drag/drop shopping demo

<img id="product1" src="images/shirt.png" alt="shirt" />
<img id="product2" src="images/cup.png" alt="cup" />
<div id="droptarget"></div>
document.observe("dom:loaded", function() {
	new Draggable("product1");
	new Draggable("product2");
	Droppables.add("droptarget", {onDrop: productDrop});
});

function productDrop(drag, drop, event) {
	alert("You dropped " + drag.id);
}
shirt cup

Sortable

Sortable.create(element or id of list,
	{ options }
);

Sortable demo

<ol id="simpsons">
	<li id="simpsons_0">Homer</li>
	<li id="simpsons_1">Marge</li>
	<li id="simpsons_2">Bart</li>
	<li id="simpsons_3">Lisa</li>
	<li id="simpsons_4">Maggie</li>
</ol>
document.observe("dom:loaded", function() {
	Sortable.create("simpsons");
});
  1. Homer
  2. Marge
  3. Bart
  4. Lisa
  5. Maggie

Sortable list events

event description
onChange when any list item hovers over a new position while dragging
onUpdate when a list item is dropped into a new position (more useful)
document.observe("dom:loaded", function() {
	Sortable.create("simpsons", {
			onUpdate: listUpdate
	});
});

Sortable list events example

document.observe("dom:loaded", function() {
	Sortable.create("simpsons", {
			onUpdate: listUpdate
	});
});

function listUpdate(list) {
	// can do anything I want here; effects, an Ajax request, etc.
	list.shake();
}
  1. Homer
  2. Marge
  3. Bart
  4. Lisa
  5. Maggie

Subtleties of Sortable events

Auto-completing text fields

autocomplete

Scriptaculous offers ways to make a text box that auto-completes based on prefix strings:

Using Autocompleter.Local

new Autocompleter.Local(
	element or id of text box, 
	element or id of div to show completions,
	array of choices, 
	{ options }
);

Autocompleter.Local demo

<input id="bands70s" size="40" type="text" />
<div id="bandlistarea"></div>
document.observe("dom:loaded", function() {
	new Autocompleter.Local(
		"bands70s",
		"bandlistarea",
		["ABBA", "AC/DC", "Aerosmith", "America", "Bay City Rollers", ...], 
		{}
	);
});

Autocompleter styling

<input id="bands70s" size="40" type="text" />
<div id="bandlistarea"></div>
#bandlistarea {
	border: 2px solid gray;
}
/* 'selected' class is given to the autocomplete item currently chosen */
#bandlistarea .selected {
	background-color: pink;
}

Using Ajax.Autocompleter

new Ajax.Autocompleter(
	element or id of text box, 
	element or id of div to show completions,
	url, 
	{ options }
);

Ajax.InPlaceEditor

new Ajax.InPlaceEditor(element or id,
	url,
	{ options }
);

Ajax.InPlaceCollectionEditor

new Ajax.InPlaceCollectionEditor(element or id,
	url,
	{
		collection: array of choices,
		options
	}
);

Playing sounds (API)

method description
Sound.play("url"); plays a sound/music file
Sound.disable(); stops future sounds from playing (doesn't mute any sound in progress)
Sound.enable(); re-enables sounds to be playable after a call to Sound.disable()
Sound.play("music/java_rap.mp3");
Sound.play("music/wazzaaaaaap.wav");

Other neat features

11.1: Event-Handling

JavaScript events

abort blur change click dblclick error focus
keydown keypress keyup load mousedown mousemove mouseout
mouseover mouseup reset resize select submit unload

Attaching event handlers the Prototype way

element.onevent = function;
element.observe("event", function);
// call the playNewGame function when the Play button is clicked
$("play").observe("click", playNewGame);

The event object

function name(event) {
	// an event handler function ...
}
method / property name description
type what kind of event, such as "click" or "mousedown"
element() * the element on which the event occurred
stop() ** cancels an event
stopObserving() removes an event handler

Mouse events

clicking
click user presses/releases mouse button on the element
dblclick user presses/releases mouse button twice on the element
mousedown user presses down mouse button on the element
mouseup user releases mouse button on the element
movement
mouseover mouse cursor enters the element's box
mouseout mouse cursor exits the element's box
mousemove mouse cursor moves around within the element's box

Mouse event objects

The event passed to a mouse handler has these properties:

mouse event
property/method description
clientX, clientY coordinates in browser window
screenX, screenY coordinates in screen
offsetX, offsetY coordinates in element (non-standard)
pointerX(),
pointerY() *
coordinates in entire web page
isLeftClick() ** true if left button was pressed

Mouse event example

<pre id="target">Move the mouse over me!</pre>
window.onload = function() {
	$("target").observe("mousemove", showCoords);
};

function showCoords(event) {
	$("target").innerHTML = 
		  "pointer: (" + event.pointerX() + ", " + event.pointerY() + ")\n"
		+ "screen : (" + event.screenX + ", " + event.screenY + ")\n"
		+ "client : (" + event.clientX + ", " + event.clientY + ")";
}
Move the mouse over me!

Recap: The keyword this

this.fieldName                  // access field
this.fieldName = value;          // modify field

this.methodName(parameters);    // call method

Recap: Event handler binding

window.onload = function() {
	$("textbox").observe("mouseout", booyah);   // bound to text box here
	$("submit").observe("click", booyah);       // bound to submit button here
};

function booyah() {           // booyah knows what object it was called on
	this.value = "booyah";
}

Fixing redundant code with this

<fieldset>
	<label><input type="radio" name="ducks" value="Huey"  /> Huey</label>
	<label><input type="radio" name="ducks" value="Dewey" /> Dewey</label>
	<label><input type="radio" name="ducks" value="Louie" /> Louie</label>
</fieldset>
function processDucks() {
	if ($("huey").checked) {
		alert("Huey is checked!");
	} else if ($("dewey").checked) {
		alert("Dewey is checked!");
	} else {
		alert("Louie is checked!");
	}
	alert(this.value + " is checked!");
}

Page/window events

namedescription
load, unload the browser loads/exits the page
resize the browser window is resized
error an error occurs when loading a document or an image
contextmenu the user right-clicks to pop up a context menu
window.onload = function() { ... };
document.observe("dom:loaded", function() {
	// attach event handlers, etc.
});

Keyboard/text events

name description
keydown user presses a key while this element has keyboard focus
keyup user releases a key while this element has keyboard focus
keypress user presses and releases a key while this element has keyboard focus
focus this element gains keyboard focus
blur this element loses keyboard focus
select this element's text is selected or deselected)

Key event objects

property name description
keyCode ASCII integer value of key that was pressed
(convert to char with String.fromCharCode)
altKey, ctrlKey, shiftKey true if Alt/Ctrl/Shift key is being held
Prototype's key code constants
Event.KEY_BACKSPACE Event.KEY_DELETE Event.KEY_DOWN Event.KEY_END
Event.KEY_ESC Event.KEY_HOME Event.KEY_LEFT Event.KEY_PAGEDOWN
Event.KEY_PAGEUP Event.KEY_RETURN Event.KEY_RIGHT Event.KEY_TAB
Event.KEY_UP

Form events

event name description
submit form is being submitted
reset form is being reset
change the text or state of a form control has changed
activate clear disable enable
focus getValue present select

Prototype form shortcuts

$F("formID")["name"]
$F("controlID")

Stopping an event

<form id="exampleform" action="http://foo.com/foo.php">...</form>
window.onload = function() {
	$("exampleform").observe("submit", checkData);
};

function checkData(event) {
	if ($F("city") == "" || $F("state").length != 2) {
		alert("Error, invalid city/state.");  // show error message 
		event.stop();
		return false;
	}
}

Event-handling example

Use events to do some cool animations!

We use timer events, with methods setInterval and clearInterval

setInterval(code,millisec) returns ID of timer event

clearInterval(id_of_setinterval)